module AboutYou
  module SDK
    module Model
      ###
      # BasketSet is a class used for adding a set of variant items into the basket
      #
      # If you want to add a set of variant items into a basket, you need to create an instance
      # of a BasketSet. The BasketSet contains BasketSetItems.
      #
      # A set can be useful if you want to sell several variants as a single product.
      # For example, if you offer a pair of shoes and additionally different styles of shoelaces
      # the customer can choose from, you maybe want to put both - shoes and laces - together.
      ###
      class BasketSet
        include AboutYou::SDK::Model::ResultError
        include AboutYou::SDK::Model::AbstractBasketItem

        # determines if an image url is required
        IMAGE_URL_REQUIRED = true

        # The ID of this basket item. You can choose this ID by yourself to identify your item later.
        attr_accessor :id
        # array containing instances of AboutYou::SDK::Model::BasketSetItem
        attr_accessor :items
        # array containing errors
        attr_accessor :errors
        # total price of the set
        attr_accessor :total_price
        # total net worth of the set
        attr_accessor :total_net
        # total vat worth of the set
        attr_accessor :total_vat
        # app id of an item
        attr_accessor :item_app_id

        ###
        # Constructor for the AboutYou::SDK::Model::BasketSet class
        #
        # * *Args*    :
        #   - +id+ -> the id of the basket set
        #   - +additional_data+ -> additional data of the basket set
        #
        # * *Returns* :
        #   - an instance of AboutYou::SDK::Model::BasketSet
        ###
        def initialize(id, additional_data = nil)
          check_id(id)
          check_additional_data(additional_data, true)
          self.id = id
          self.additional_data = additional_data

          self
        end

        ###
        # This method is used for creating a basket set with a given api json
        # response. It is best practice to use this method.
        #
        # * *Args*    :
        #   - +json_object+ -> the api response key
        #   - +factory+ -> instance of AboutYou::SDK::Factory::DefaultModelFactory
        #   - +products+ -> Array of products
        #
        # * *Returns* :
        #   - an instance of AboutYou::SDK::Model::BasketSet
        ###
        def create_from_json(json_object, factory, products)
          set = new(
            json_object['id'],
            if json_object.key?('additional_data')
              [json_object['additional_data']]
            else
              nil
            end
            )

          set.parse_error_result(json_object)

          json_object['set_items'].each do |index, json_term|
            item = factory.create_basket_set_item(json_term, products)
            if item.errors?
              set.errors[index] = item
            else
              set.items[index] = item
            end
          end
          if json_object.key?('total_price')
            set.totalPrice = json_object['total_price']
          end
          if json_object.key?('total_net')
            set.totalPrice = json_object['total_net']
          end
          if json_object.key?('total_vat')
            set.totalPrice = json_object['total_vat']
          end

          set
        end

        ###
        # This method is used for creating a basket set from an array containing
        # instances of AboutYou::SDK::Model::BasketSetItem
        #
        # * *Args*    :
        #   - +item_id+ -> the id of the set
        #   - +sub_items+ -> Array containing instances of AboutYou::SDK::Model::BasketSetItem
        #   - +additional_data+ -> additional data of the basket set
        #
        # * *Returns* :
        #   - an instance of AboutYou::SDK::Model::BasketSet
        ###
        def create(item_id, sub_items, additional_data = nil)
          set = new(item_id, additional_data)

          sub_items.each do |item_data|
            set.add_item(
              AboutYou::SDK::Model::BasketSetItem.new(
                item_data[0],
                item_data[1] ? item_data[1] : nil
              )
            )
          end

          set
        end

        ###
        # This method is used for adding items to a basket set
        #
        # * *Args*    :
        #   - +item+ -> instance of AboutYou::SDK::Model::BasketSetItem
        #
        # * *Fails* :
        #   - if the app id of the set and item diverge
        ###
        def add_item(item)
          if items.count == 0
            self.item_app_id = item.app_id
          elsif item_app_id != item.app_id
            fail '\InvalidArgumentException! you can not set different app ids
              for items in an item-set.'
          end

          items.push(item)
        end

        ###
        # This method checks if there are errors in the basket set
        #
        # * *Returns* :
        #   - Boolean determining whether there are errors or not
        ###
        def errors?
          error_code || errors.count > 0
        end

        ###
        # This method is used for creating a unique key for the basket set
        #
        # * *Returns* :
        #   - a String containing a unique key for the basket set
        ###
        def unique_key
          key = ':'
          unless additional_data
            additional_data.sort!
            key = key + ':' + additional_data.to_json
          end

          items = []
          self.items.each do |item|
            items.push(item.unique_key)
          end
          key += items.to_json

          key
        end

        ###
        # This method is used for determining whether a certain id is valid for
        # the basket set or not
        #
        # * *Args*    :
        #   - +id+ -> the id which should be checked
        #
        # * *Fails* :
        #   - if the id is not a String and its length is smaller then 2
        ###
        def check_id(id)
          fail '\InvalidArgumentException! ID of the BasketSetItem must be a
            String that must contain minimum two characters' unless
              id.is_a?(String) && id.length > 1
        end
      end
    end
  end
end
